package com.ts.api.module.api.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.gitee.apanlh.util.algorithm.digest.MD5;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.util.reflection.CopyUtils;
import com.gitee.apanlh.util.valid.Assert;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.model.RequestHeader;
import com.ts.api.common.constant.api.ApiEnum;
import com.ts.api.common.constant.api.ApiServiceCodeEnum;
import com.ts.api.common.context.ApiContext;
import com.ts.api.exp.ApiMsgException;
import com.ts.api.module.api.entity.bo.ApiDecryptBO;
import com.ts.api.module.api.entity.bo.ApiEncryptBO;
import com.ts.api.module.api.entity.bo.ApiHeaderBO;
import com.ts.api.module.api.entity.bo.ApiMsgBO;
import com.ts.api.module.api.entity.po.ApiKeyPO;
import com.ts.api.module.api.entity.po.ApiLogPO;
import com.ts.api.module.api.service.ApiRequestValidateService;
import com.ts.cache.apikey.ApiKeyCacheService;
import com.ts.cache.apikey.entity.ApiKeyCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class ApiRequestValidateServiceImpl implements ApiRequestValidateService {

    @Autowired
    private ApiKeyCacheService apiKeyCacheService;

    @Override
    public ApiHeaderBO validHeader(RequestHeader header) throws ApiMsgException {
        return ApiHeaderBO.createBO(header).valid();
    }

    @Override
    public ApiKeyPO validClient(String clientId) {
        ApiKeyCache apiKeyCache = apiKeyCacheService.get(clientId);
        Assert.isNotNullThrows(apiKeyCache, new ApiMsgException(ApiEnum.API_CLIENT_ID_ERROR));
        Assert.isFalseThrows(null == apiKeyCache.getStatus() || Eq.objectOr(apiKeyCache.getStatus(), 0), new ApiMsgException(ApiEnum.API_CLIENT_DISABLE));

        //  记录业务信息
        ApiLogPO logPO = ApiContext.LOG_OBJECT.get();
        if (ValidParam.isNotNull(logPO)) {
            logPO.setApiClientId(apiKeyCache.getApiClientId());
            logPO.setEnvType(apiKeyCache.getApiEnvType());
            logPO.setApiAccessProviderType(apiKeyCache.getApiAccessProviderType());
        }
        return CopyUtils.copy(apiKeyCache, ApiKeyPO.class);
    }

    @Override
    public void validAccess(ApiKeyPO apiKeyPO, Integer providerType) {
        Assert.isNotNullThrows(apiKeyPO, new ApiMsgException(ApiEnum.API_CLIENT_ID_ERROR));
        Assert.isFalseThrows(null == apiKeyPO.getStatus() || Eq.objectOr(apiKeyPO.getStatus(), 0), new ApiMsgException(ApiEnum.API_CLIENT_DISABLE));

        Assert.isTrueThrows(Eq.object(providerType, apiKeyPO.getApiAccessProviderType()), new ApiMsgException(ApiEnum.API_ACCESS_UNAUTHORIZED));
    }

    @Override
    public ApiMsgBO validSign(ApiHeaderBO headerBO, String body, ApiKeyPO apiKeyPO) throws ApiMsgException {
        String data = String.valueOf(JSONObject.parseObject(body).get("data"));
        Assert.isNotEmptyThrows(data, new ApiMsgException(ApiEnum.API_BODY_DATA_ERROR));

        ApiDecryptBO apiDecryptBO = this.decrypt(apiKeyPO, data);
        String content = apiDecryptBO.getContent();

        ApiContext.DECRYPT_DATA.set(content);

        //  排序
        Map<String, Object> map = JsonUtils.toMapOrder(content);
        Map<String, Object> tree = MapUtils.newTreeMap(map);

        Assert.isTrueThrows(MapUtils.eqByOrder(tree, map), new ApiMsgException(ApiEnum.API_SIGN_SORT_DATA_ERROR));
        Assert.isTrueThrows(Eq.str(headerBO.getSign(), MD5.create().digestToHex(StringUtils.append(content, headerBO.getClientId(), headerBO.getTimestamp()))), new ApiMsgException(ApiEnum.API_SIGN_ERROR));

        return ApiMsgBO.createBO(content, ApiServiceCodeEnum.get(headerBO.getServiceCode()), apiDecryptBO.getCacheKey());
    }

    @Override
    public ApiEncryptBO encrypt(ApiKeyPO apiKeyPO, String ciphertext) throws ApiMsgException {
        return ApiEncryptBO.aes(ciphertext, apiKeyPO);
    }

    @Override
    public ApiDecryptBO decrypt(ApiKeyPO apiKeyPO, String ciphertext) throws ApiMsgException {
        return ApiDecryptBO.aes(ciphertext, apiKeyPO);
    }
}
